package hello.app;

import hello.app.model.CommentModel;
import hello.app.model.HelloApi;
import hello.app.model.HelloContactModel;
import hello.app.model.HelloApi.HelloApiException;
import hello.app.model.ModelManager;
import hello.app.model.data.Comment;
import hello.app.model.data.HelloContact;
import hello.app.model.data.MyContact;
import hello.app.util.AdteAsyncTask;
import hello.app.util.AdteToast;
import hello.app.util.Debug;
import hello.app.util.GoogleSearch;
import hello.app.util.Util;
import hello.app.util.GoogleSearch.Result;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.telephony.PhoneNumberUtils;
import android.widget.Toast;


public class PhoneHandler {
	private HelloApi mApi;
	private ModelManager mManager;
	private Context mContext;
	private State mPrevState;
	private RingStorage mStorage;
	private ContactNotification mNotification;

	private static final int TOAST_LINE_NUM = 17;

	enum State {
		RingRing, OffHook, Idel, None
	}

	class ContactNotification implements AdteToast.CancelListener{
		private StringBuilder mMsg;
		private AdteToast mToast;

		ContactNotification(){
			mMsg = new StringBuilder();
			mToast = AdteToast.getInstance(mContext);
			mToast.setCancelListener(this);
		}

		public ContactNotification addMessage(String msg){
			mMsg.append(msg);
			return this;
		}

		public void show(int pos){
			mToast.show(mMsg.toString(), pos);
			mMsg = new StringBuilder();
		}

		public void cancel(){
			mToast.cancel();
		}

		public void onCancel() {
			mMsg = new StringBuilder();
		}
	}

	class RingStorage {
		HelloContact mContact = null;
		String mNumber = "";

		public void saveContact(HelloContact c) {
			this.mContact = c;
		}

		public void saveNumber(String number) {
			this.mNumber = number;
		}

		public HelloContact getContact() {
			return mContact;
		}

		public String getNumber() {
			return mNumber;
		}

		public boolean isEmptyContact() {
			return mContact == null ? true : false;
		}

		public boolean isEmptyNumber() {
			if (mNumber == null) {
				mNumber = "";
			}
			return mNumber.length() == 0 ? true : false;
		}

		public boolean saved() {
			return !isEmptyContact() && !isEmptyNumber();
		}

		public void reset() {
			this.mContact = null;
			this.mNumber = "";
		}
	}

	public class RecursiveTask extends TimerTask {
		private String mNumber;
		private int mCounter;
		public RecursiveTask(String number, int counter){
			mNumber = number;
			mCounter = counter;
		}
		public void run() {
			onRinging(mNumber,mCounter);
		}
	}

	public PhoneHandler(Context context) {

		mManager = ModelManager.getInstatce(context);
		mApi = mManager.getHelloApi();
		mPrevState = State.None;
		mStorage = new RingStorage();
		this.mContext = context;
		mNotification = new ContactNotification();
	}

	private String getToastMessage(HelloContact c) {
		StringBuilder msg = new StringBuilder();
		String good = mContext.getString(R.string.good);
		String bad = mContext.getString(R.string.bad);
		String number = c.getNumber();
		String address = getSuitableText(c.getAddress());
		String type = c.getTypeName();
		String name = getSuitableText(c.getName());

		if (Util.isMobile(number)) {
			if (!mManager.getHelloSetting().isSuperUser()) {
				msg.append(String.format(
						"携帯\n%s:?? %s:??\n※携帯番号の評価は表示されません\nアップグレード版では表示されます",
						good, bad));
			} else {
				msg.append(String.format("携帯\n%s:%d %s:%d", good, c.getGood(), bad, c.getBad()));
			}
		} else {
			if (type.length() != 0) {
				msg.append(String.format("~%s~\n", type));
			}
			if (name.length() != 0) {
				msg.append(String.format("%s\n", name));
			}
			if (address.length() != 0) {
				msg.append(String.format("%s\n", address));
			}
			msg.append(String.format("%s:%d %s:%d", good, c.getGood(), bad,c.getBad()));
		}
		//口コミを表示する件数を取得
		int showLine = mManager.getHelloSetting().getCommentLineNumber();
		Comment[] cmts = c.getComments();
		if(cmts.length != 0 && showLine != 0){
			msg.append("\n--口コミ--");
		}
		for(int i = 0; i < cmts.length && i < showLine; i++){
			String text = Util.suitableString(cmts[i].getText(), 40);
			msg.append(String.format("\n・%s", text));
			//Debug.log(Util.insertNewLine(cmts[i].getText(),5));
		}
		return msg.toString();
	}

	private void displayEvalation(String number)
			throws ClientProtocolException, HelloApiException,
			URISyntaxException, IOException, JSONException {
		// 履歴は必ず挿入
		if(number.length() == 0)
			return;

		HelloContact contact = mApi.getContact(number);
		if (contact != null) {
			MyContact[] my = getMyContact(number);
			if (my != null) {
				contact.setName(my[0].getName());
			}
			// 評価通知
			String name = contact.getName();
			String msg = getToastMessage(contact);
			mNotification.addMessage(msg);

			// 評価対象もコンタクトをローカルに保存
			HelloContactModel contactModel = mManager.getHelloContactModel();
			CommentModel cmtModel = mManager.getCommentModel();
			contactModel.save(contact);
			for(Comment cmt : contact.getComments()){
				cmtModel.save(cmt);
			}
			if(!Util.isSet(name) && !Util.isMobile(number) && contact.getComments().length == 0 && mManager.getHelloSetting().isGoogleEnabled()){
				AdteAsyncTask task = new AdteAsyncTask();
				task.setBackgroundRunner(new AdteAsyncTask.BackgroundRunner() {
					public Object exec(Object... args) {
						ArrayList<GoogleSearch.Result> ret = new ArrayList<GoogleSearch.Result>();
						try {
							GoogleSearch google = new GoogleSearch();
							for(GoogleSearch.Result r : google.getResult(PhoneNumberUtils.formatNumber((String)args[0]))){
								ret.add(r);
							}
						} catch (Exception e){
							Debug.error(e.getMessage());
						}
						return ret;
					}
				});
				task.setPostRunner(new AdteAsyncTask.FinishRunner() {
					public void onFinish(Object result) {
						if(result instanceof ArrayList && result != null){
							ArrayList<GoogleSearch.Result> results = (ArrayList<GoogleSearch.Result>)result;
							StringBuilder sb = new StringBuilder();
							sb.append("・検索結果");
							if(results.size() != 0){
								for(Result r : results){
									String title = Util.removeHtmlTag(r.getTitle());
									sb.append(String.format("\nタイトル:%s", title));
								}
							}else{
								sb.append("\n検索結果にHitしませんでした");
							}
							mNotification.addMessage("\n" +sb.toString());
							if(mPrevState != State.Idel)
								mNotification.show(mManager.getHelloSetting().getDisplayPostion());
						}
					}
				});
				task.setDelayTime(1);
				task.execute(number);
			}else{
				mNotification.show(mManager.getHelloSetting().getDisplayPostion());
			}

			/*
			if (!Util.isSet(name) && !Util.isMobile(number)
					&& setting.isGoogleEnabled()) {
				googleNotification(number);
			}*/

			mStorage.saveContact(contact);
			mStorage.saveNumber(number);
		}
	}

	private synchronized void onRinging(String number, int counter){
		Debug.log("onRinging counter : " + Integer.toString(counter));
		if(counter < 3){
			try {
				displayEvalation(number);
			} catch (Exception e) {
				counter++;
				Timer timer = new Timer();
				timer.schedule(new RecursiveTask(number, counter), 750);
			} finally {
				mPrevState = State.RingRing;
			}
		}
	}

	public synchronized void onRinging(String number) {
		if(mPrevState == State.RingRing)
			return ;
		Debug.log("CALL_STATE_RINGING");
		try {
			displayEvalation(number);
		}catch (UnknownHostException e) {
			Toast.makeText(mContext, mContext.getString(R.string.error_network), Toast.LENGTH_SHORT).show();
		}catch (Exception e) {
			Debug.error(e.getMessage());
			Timer timer = new Timer();
			timer.schedule(new RecursiveTask(number, 0), 750);
		} finally {
			mPrevState = State.RingRing;
		}
	}

	public synchronized void onOffHook(String number) {

		if(mPrevState == State.OffHook)
			return;
		Debug.log("CALL_STATE_OFFHOOK");
		//mNotification.cancel();
		mPrevState = State.OffHook;
		/*
		try {
			//前の状態が着信でなかったら
			if(state != State.RingRing){
				Debug.log("number : " + number);
				displayEvalation(number);
			}else{
				if (toast != null) {
					toast.cancel();
				}
			}
		} catch (Exception e) {

		} finally {
			state = State.OffHook;
		}*/

	}

	public synchronized void onIdle() {

		if(mPrevState == State.Idel)
			return;

		Debug.log("CALL_STATE_IDLE");
		if (mPrevState == State.OffHook && mStorage.saved()) {
			// 受話器をとりコンタクトが取得できていたら
			HelloContact c = mStorage.getContact();
			String contact_id = String.valueOf(c.getId());
			String condition = HelloContact.ID + " = " + contact_id	+ " and " + HelloContact.EVALUATED + " = 0";
			// すでに評価されたコンタクトなら評価ダイアログをださない
			HelloContact[] ap = mManager.getHelloContactModel().find(null,condition, null);
			if(mManager.getHelloSetting().isShowCommentDlgEnabled()){
				CommentActivity.start(c, mContext);
			}
			if ((ap != null && ap.length != 0) && mManager.getHelloSetting().isEvalEnabled()) {
				EvaluationActicity.start(c, mContext);
			}
		}
		if(mPrevState == State.RingRing){
			setMissedNotification();
		}
		//mNotification.cancel();
		mStorage.reset();
		mPrevState = State.Idel;
	}

	private void setMissedNotification(){
		NotificationManager nm = (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
		Notification n = new Notification(); // Notificationの生成
		n.icon = R.drawable.mini_icon;
		n.tickerText = mContext.getString(R.string.status_bar_missed);
		// PendingIntentの生成
		Intent i = new Intent(mContext.getApplicationContext(), HistoryActivity.class);
		PendingIntent pi = PendingIntent.getActivity(mContext, 0, i, 0);
		// 詳細情報の設定とPendingIntentの設定
		n.setLatestEventInfo(mContext.getApplicationContext(), Application.TITLE, mContext.getString(R.string.status_bar_missed), pi);
		nm.notify(1, n); // 生成したNotificationを通知する
	}

	private MyContact[] getMyContact(String number) {
		MyContact[] con = mManager.getMyContactModel().find(
				new String[] { Phone.DISPLAY_NAME, Phone.DATA1, },
				Phone.DATA1 + "='" + PhoneNumberUtils.formatNumber(number)
						+ "'", null);

		return con;

	}

	private String getSuitableText(String text) {
		return Util.suitableString(text, TOAST_LINE_NUM);
	}
}
